import React, { ComponentType } from 'react';
import RouterContext from './context';
import { pathToRegexp, Key } from 'path-to-regexp';
import { RouteComponentProps, match } from './';
import { LocationDescriptor } from '../history';
//在TS当你定义一个类的时候，其它得到二个类型，第一个是类的实例的类型，第二个是类的构造函数类型
//JSXElementConstructor=
interface RouteProps {
    path?: LocationDescriptor;
    exact?: boolean;
    component?: ComponentType<RouteComponentProps<any>> | ComponentType<any>;
    render?: (props: RouteComponentProps<any>) => React.ReactNode;
    children?: (props: RouteComponentProps<any>) => React.ReactNode;
}
//Route的核心作用是判断当前组件的 path属性和浏览器的路径是否一致
export default class extends React.Component<RouteProps> {
    //如果一个类有一这样的一个属性static contextType，那么内部this.context=RouterContext.Provider.value
    static contextType = RouterContext;
    //什么时候会用 Consumer--->函数组件里, contextType ---> 类组件
    render() {
      const { path = '/', component: RouteComponent, exact = false, render, children } = this.props;
      //我们要通过this.context获取路径,然后跟Route的path去比较
      const pathname = this.context.location.pathname;
      const keys: Array<Key> = [];
      const routePath: string = typeof path == 'object' ? path.pathname : path;
      const regexp = pathToRegexp(routePath, keys, { end: exact });
      const result: Array<string> = pathname.match(regexp);
      const routeComponentProps: RouteComponentProps<any> = {
        location: this.context.location,
        history: this.context.history
      };
        //pathname="/user/detail/1" path="/user/detail/:id"
        //result=['/user/detail/1','1']
      if (result) {
        const [url, ...values] = result;//url=/user/detail/1 values=['1']
        const paramNames = keys.map((key: Key) => key.name);//['id']
        const memo: Record<string, any> = {};
        const params = values.reduce((memo: Record<string, any>, value: string, index: number) => {
          memo[paramNames[index]] = value;
          return memo;
        }, memo);//params={id:'1'}

        type Params = typeof params;
        const matchResult: match<Params> = {
          params,
          isExact: url === path,
          path: routePath, // 你给<Route/>上设置的path属性
          url // 当前浏览器URL栏显示的路径
        };
        //如果路径匹配，则match属性指向匹配对象
        routeComponentProps.match = matchResult;
        if (RouteComponent) { //渲染的是路由对应的页面组件
          return <RouteComponent {...routeComponentProps} />;
        } else if (render) {
          return render(routeComponentProps);
        } else if (children) {  //渲染的是MenuLink 并且匹配上了路径 会带上match对象 内部会根据此将link高亮
          return children(routeComponentProps);
        } else {
          return null;
        }

      } else {
        if (children) { //渲染的是MenuLink 没有匹配上的 也就是说routeComponentProps中不包含 match对象, 也就不会高亮显示
          return children(routeComponentProps);
        } else {
          return null;
        }
      }

    }
}
